#coding=utf-8
import sys
import pika
import time
import random
"""
在数据处理结束后发送ack，这样RabbitMQ Server会认为Message Deliver 成功。
持久化queue，可以防止RabbitMQ Server 重启或者crash引起的数据丢失。
持久化Message，理由同上。

答案是否定的。问题就在与RabbitMQ需要时间去把这些信息存到磁盘上，这个time window虽然短，但是它的确还是有。在这个时间窗口内如果数据没有保存，数据还会丢失。还有另一个原因就是RabbitMQ并不是为每个Message都做fsync：它可能仅仅是把它保存到Cache里，还没来得及保存到物理磁盘上。

因此这个持久化还是有问题。但是对于大多数应用来说，这已经足够了。当然为了保持一致性，你可以把每次的publish放到一个transaction中。这个transaction的实现需要user defined codes。

那么商业系统会做什么呢？一种可能的方案是在系统panic时或者异常重启时或者断电时，应该给各个应用留出时间去flash cache，保证每个应用都能exit gracefully。
"""

class RbMQProducer(object):

    def __init__(self):
        self.connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))

    def send_message(self):

        channel = self.connection.channel()
        channel.queue_declare(queue='hello')

        for i in xrange(10):
            time.sleep(1)
            message = " ".join(sys.argv[1:]) or "hello world! i am {}".format(i)
            channel.basic_publish(exchange='',
                                  routing_key='hello',
                                  body=message)
            print(" [x] Sent 'Hello World!'")

    def send_message_durable(self):
        channel = self.connection.channel()
        channel.queue_declare(queue='hello',durable=True)

        for i in xrange(10):
            time.sleep(1)
            message = " ".join(sys.argv[1:]) or "hello world! i am {}".format(i)
            channel.basic_publish(exchange='',
                                  routing_key="hello",
                                  body=message,
                                  properties=pika.BasicProperties(
                                      delivery_mode=2,    #make the message persistent
                                  ))

    def exchange_message(self):
        channel = self.connection.channel()
        channel.exchange_declare(exchange='logs',type='fanout')
        for i in xrange(10):
            message = " ".join(sys.argv[1:]) or "exchange info : Hello world {}!".format(i)
            channel.basic_publish(exchange='logs',
                                  routing_key='',
                                  body=message)
            print " [{}] send {}".format(i,message)
            time.sleep(1.5)

    def direct_message(self):
        channel = self.connection.channel()
        channel.exchange_declare(exchange='direct_logs',
                                 type='direct')
        severity = sys.argv[1] if len(sys.argv)>1 else ['info','warning','error']
        for i in xrange(10):
            message = " ".join(sys.argv[2:]) or 'hello world!'
            routing_key_random = severity[random.randint(0,len(severity)-1)]
            channel.basic_publish(exchange='direct_logs',
                                  routing_key=routing_key_random,
                                  body=message)
            print "[{}]: {}".format(routing_key_random,message)
            time.sleep(1.5)

    def topic_message(self):
        channel = self.connection.channel()
        channel.exchange_declare(exchange='topic_logs',
                                 type='topic')
        routing_key = sys.argv[1] if len(sys.argv)>1 else ["anonymous.info","lck.info","lck.error"]
        for i in xrange(10):
            routing_key_value = routing_key[random.randint(0,len(routing_key)-1)]
            message = " ".join(sys.argv[2:]) or "hello world! "
            channel.basic_publish(exchange='topic_logs',
                                  routing_key=routing_key_value,
                                  body=message)
            print "[{}] : {}".format(routing_key_value,message)
            time.sleep(1.5)

    def rpc_message(self):
        channel = self.connection.channel()
        channel.queue_declare(queue='rpc_queue')
        channel.basic_qos(prefetch_count=1)
        channel.basic_consume(self.on_request,queue='rpc_queue')
        print "[x] Awaiting rpc requests"
        channel.start_consuming()

    def on_request(self,ch, method, props, body):
        n = int(body)
        response = random.randint(100,1000)
        print "[.]{}".format(response)
        ch.basic_publish(exchange='',
                         routing_key=props.reply_to,
                         properties=pika.BasicProperties(correlation_id=props.correlation_id),
                         body=str(response))
        ch.basic_ack(delivery_tag=method.delivery_tag)





    def __del__(self):
        self.connection.close()



if __name__ == "__main__":
    rm_producer = RbMQProducer()
    # rm_producer.send_message()
    # rm_producer.send_message_durable()

    # rm_producer.exchange_message()
    # rm_producer.direct_message()
    # rm_producer.topic_message()
    rm_producer.rpc_message()